package com.shop.loan.redis;

import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Tuple;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * redis 工具类
 */
@Component
public class RedisUtil {
//
//    @Autowired
//    RedisPoolFactory redisPoolFactory;

    @Resource
    JedisPool jedisPool;

    /**
     * 获取指定key的值,如果key不存在返回null，如果该Key存储的不是字符串，会抛出一个错误
     *
     * @param key
     * @return
     */
    public String get(String key) {
        Jedis jedis = getJedis();
        try {
            return jedis.get(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 设置key的值为value
     *
     * @param key
     * @param value
     * @return
     */
    public String set(String key, String value) {
        Jedis jedis = getJedis();
        try {
            return jedis.set(key, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 删除指定的key,也可以传入一个包含key的数组
     *
     * @param keys
     * @return
     */
    public Long del(String... keys) {
        Jedis jedis = getJedis();
        try {
            return jedis.del(keys);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过key向指定的value值追加值
     *
     * @param key
     * @param str
     * @return
     */
    public Long append(String key, String str) {
        Jedis jedis = getJedis();

        try {
            return jedis.append(key, str);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 判断key是否存在
     *
     * @param key
     * @return
     */
    public Boolean exists(String key) {
        Jedis jedis = getJedis();
        try {
            return jedis.exists(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return false;
    }

    /**
     * 设置key value,如果key已经存在则返回0
     *
     * @param key
     * @param value
     * @return
     */
    public Long setnx(String key, String value) {
        Jedis jedis = getJedis();
        try {
            return jedis.setnx(key, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return 0L;
    }

    /**
     * 设置key value并指定这个键值的有效期
     *
     * @param key
     * @param seconds
     * @param value
     * @return
     */
    public String setex(String key, int seconds, String value) {
        Jedis jedis = getJedis();
        try {
            return jedis.setex(key, seconds, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过key 和offset 从指定的位置开始将原先value替换
     *
     * @param key
     * @param offset
     * @param str
     * @return
     */
    public Long setrange(String key, int offset, String str) {
        Jedis jedis = getJedis();
        try {
            return jedis.setrange(key, offset, str);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过批量的key获取批量的value
     *
     * @param keys
     * @return
     */
    public List<String> mget(String... keys) {
        Jedis jedis = getJedis();
        try {
            return jedis.mget(keys);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 批量的设置key:value,也可以一个
     *
     * @param keysValues
     * @return
     */
    public String mset(String... keysValues) {
        Jedis jedis = getJedis();
        try {
            return jedis.mset(keysValues);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 批量的设置key:value,可以一个,如果key已经存在则会失败,操作会回滚
     *
     * @param keysValues
     * @return
     */
    public Long msetnx(String... keysValues) {
        Jedis jedis = getJedis();
        try {
            return jedis.msetnx(keysValues);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 设置key的值,并返回一个旧值
     *
     * @param key
     * @param value
     * @return
     */
    public String getSet(String key, String value) {
        Jedis jedis = getJedis();
        try {
            return jedis.getSet(key, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过下标 和key 获取指定下标位置的 value
     *
     * @param key
     * @param startOffset
     * @param endOffset
     * @return
     */
    public String getrange(String key, int startOffset, int endOffset) {
        Jedis jedis = getJedis();
        try {
            return jedis.getrange(key, startOffset, endOffset);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过key 对value进行加值+1操作,当value不是int类型时会返回错误,当key不存在是则value为1
     *
     * @param key
     * @return
     */
    public Long incr(String key) {
        Jedis jedis = getJedis();
        try {
            return jedis.incr(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过key给指定的value加值,如果key不存在,则这是value为该值
     *
     * @param key
     * @param integer
     * @return
     */
    public Long incrBy(String key, long integer) {
        Jedis jedis = getJedis();
        try {
            return jedis.incrBy(key, integer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 对key的值做减减操作,如果key不存在,则设置key为-1
     *
     * @param key
     * @return
     */
    public Long decr(String key) {
        Jedis jedis = getJedis();
        try {
            return jedis.decr(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 减去指定的值
     *
     * @param key
     * @param integer
     * @return
     */
    public Long decrBy(String key, long integer) {
        Jedis jedis = getJedis();
        try {
            return jedis.decrBy(key, integer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过key获取value值的长度
     *
     * @param key
     * @return
     */
    public Long strLen(String key) {
        Jedis jedis = getJedis();
        try {
            return jedis.strlen(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过key给field设置指定的值,如果key不存在则先创建,如果field已经存在,返回0
     *
     * @param key
     * @param field
     * @param value
     * @return
     */
    public Long hsetnx(String key, String field, String value) {
        Jedis jedis = getJedis();
        try {
            return jedis.hsetnx(key, field, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过key给field设置指定的值,如果key不存在,则先创建
     *
     * @param key
     * @param field
     * @param value
     * @return
     */
    public Long hset(String key, String field, String value) {
        Jedis jedis = getJedis();
        try {
            return jedis.hset(key, field, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return 0L;
    }

    /**
     * 获取某个key
     * @param key
     * @return
     */
    public Map<String, String> hGetMap(String key) {
        Jedis jedis = getJedis();
        try {
            return jedis.hgetAll(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }


    /**
     * 通过key同时设置 hash的多个field
     *
     * @param key
     * @param hash
     * @return
     */
    public String hmset(String key, Map<String, String> hash) {
        Jedis jedis = getJedis();
        try {
            return jedis.hmset(key, hash);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过key 和 field 获取指定的 value
     *
     * @param key
     * @param failed
     * @return
     */
    public String hget(String key, String failed) {
        Jedis jedis = getJedis();
        try {
            return jedis.hget(key, failed);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 设置key的超时时间为seconds
     *
     * @param key
     * @param seconds
     * @return
     */
    public Long expire(String key, long seconds) {
        Jedis jedis = getJedis();
        try {
            return jedis.expire(key, seconds);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return 0L;
    }

    /**
     * 通过key 和 fields 获取指定的value 如果没有对应的value则返回null
     *
     * @param key
     * @param fields 可以是 一个String 也可以是 String数组
     * @return
     */
//    public List<String> hmget(String key, String... fields) {
//        Jedis jedis = getJedis();
//        try {
//            return jedis.hmget(key, fields);
//        }catch (Exception e){
//            e.printStackTrace();
//        }finally {
//            close(jedis);
//        }
//        return null;
//    }

    /**
     * 通过key给指定的field的value加上给定的值
     *
     * @param key
     * @param field
     * @param value
     * @return
     */
    public Long hincrby(String key, String field, Long value) {
        Jedis jedis = getJedis();
        try {
            return jedis.hincrBy(key, field, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过key和field判断是否有指定的value存在
     *
     * @param key
     * @param field
     * @return
     */
    public Boolean hHasKey(String key, String field) {
        Jedis jedis = getJedis();
        try {
            return jedis.hexists(key, field);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return false;
    }

    /**
     * 通过key返回field的数量
     *
     * @param key
     * @return
     */
    public Long hlen(String key) {
        Jedis jedis = getJedis();
        try {
            return jedis.hlen(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过key 删除指定的 field
     *
     * @param key
     * @param fields 可以是 一个 field 也可以是 一个数组
     * @return
     */
    public Long hdel(String key, String... fields) {
        Jedis jedis = getJedis();
        try {
            return jedis.hdel(key, fields);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }

    /**
     * 通过key判断值得类型
     *
     * @param key
     * @return
     */
    public String type(String key) {
        Jedis jedis = getJedis();
        try {
            return jedis.type(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return null;
    }


    /**
     * 存储REDIS队列 顺序存储
     *
     * @param key   reids键名
     * @param value 键值
     */
    public void lpush(String key, String value) {
        Jedis jedis = getJedis();
        try {
            jedis.lpush(key, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //返还到连接池
            close(jedis);
        }
    }

    /**
     * 存储REDIS队列 反向存储
     *
     * @param key   reids键名
     * @param value 键值
     */
    public void rpush(String key, String value) {
        Jedis jedis = getJedis();
        try {
            jedis.rpush(key, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //返还到连接池
            close(jedis);
        }
    }

    /**
     * 将列表的最后一个元素弹出，并返回给客户端
     *
     * @param key reids键名
     */
    public Object rpop(String key) {
        Jedis jedis = getJedis();
        try {
            return jedis.rpop(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //返还到连接池
            close(jedis);
        }
        return null;
    }


    public Long llen(byte[] key) {
        Jedis jedis = getJedis();
        try {
            return jedis.llen(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //返还到连接池
            close(jedis);
        }
        return 0L;
    }

    /**
     * 获取队列数据
     *
     * @param key 键名
     * @return
     */
    public List lpopList(byte[] key) {
        List list = null;

        Jedis jedis = getJedis();
        try {
            list = jedis.lrange(key, 0, -1);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //返还到连接池
            close(jedis);
        }
        return list;
    }

    /**
     * 查询某个key数量
     *
     * @param key
     * @return
     */
    public int getKeyCount(String key) {
        Jedis jedis = getJedis();
        try {
            Set<String> stringSet = jedis.keys(key + "*");
            return stringSet.size();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //返还到连接池
            close(jedis);
        }
        return 0;
    }

    /**
     * 添加元素
     *
     * @param key
     * @param score
     * @param value
     */
    public void zAdd(String key, double score, String value) {
        Jedis jedis = getJedis();
        try {
            jedis.zadd(key, score, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
    }

    /**
     * 获取索引区间内的元素
     *
     * @param key
     * @param start 起始索引
     * @param end   终止索引
     * @return
     */
    public Set<String> zRange(String key, long start, long end) {
        Jedis jedis = getJedis();
        Set<String> set = null;
        try {
            set = jedis.zrange(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return set;
    }

    /**
     * 获取索引区间内的元素(根据分数降序)
     *
     * @param key
     * @param start 起始索引
     * @param end   终止索引
     * @return
     */
    public Set<String> zRevRange(String key, long start, long end) {
        Jedis jedis = getJedis();
        Set<String> set = null;
        try {
            set = jedis.zrevrange(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return set;
    }


    public Set<Tuple> zRangeWithScores(String key, long start, long end) {
        Jedis jedis = getJedis();
        Set<Tuple> set = null;
        try {
            set = jedis.zrangeWithScores(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return set;
    }


    /**
     * 获取分数区间内的元素
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public Set<String> zRangeByScore(String key, double min, double max) {
        Jedis jedis = getJedis();
        Set<String> set = null;
        try {
            set = jedis.zrangeByScore(key, min, max);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return set;
    }

    /**
     * 获取分数区间内的元素 并且返回分数
     *
     * @param key
     * @param min
     * @param max
     * @return
     */
    public Set<Tuple> zRangeByScoreWithScores(String key, long min, long max) {
        Jedis jedis = getJedis();
        Set<Tuple> set = null;
        try {
            set = jedis.zrangeByScoreWithScores(key, min, max);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return set;
    }

    /**
     * 获取元素数量
     *
     * @param key
     * @return
     */
    public Long zCard(String key) {
        Jedis jedis = getJedis();
        Long number = null;
        try {
            number = jedis.zcard(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
        return number;
    }


    /**
     * 删除单个元素
     *
     * @param key
     * @param value
     */
    public void zRem(String key, String value) {
        Jedis jedis = getJedis();
        try {
            jedis.zrem(key, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
    }

    /**
     * 删除元素数组
     *
     * @param key
     * @param values
     */
    public void zRem(String key, String[] values) {
        Jedis jedis = getJedis();
        try {
            jedis.zrem(key, values);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            close(jedis);
        }
    }


    private void close(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }

    public void flush(String password) {
        Jedis jedis = getJedis();
        if (jedis != null && password != null && password.trim().equals("2019.wallet")) {
            jedis.flushDB();
        }
    }

    public synchronized Jedis getJedis() {
        return jedisPool.getResource();
    }

}
